/**
    Header files
*/

/**
    Own header
*/
#include "libServer.h"

#include "dbusCommon.h"

/**
    System header
*/
#include <gio/gio.h>        // GIO for dbus
#include <glib-2.0/glib.h>  // GLIB for main loop
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

/**
    Instance init
*/
static GMainLoop *pLoop = NULL;
static RTplayGdbusExample *pSkeleton = NULL;
static int callNum = 0;

static void *run(void *);
static int thread_create(void);

/**
    Normal functions
*/
static gboolean Emit_My_signal1(gconstpointer p)
{
    g_print("Emit_My_Signal1() is called.\n");

    gchar buf[20];
    memset(buf, 0, 20);
    callNum++;
    sprintf(buf, "Server Signal1(%d)", callNum);

    rtplay_gdbus_example_emit_my_signal1(pSkeleton, buf);

    return TRUE;
}

static gboolean Emit_My_Signal2(gconstpointer p)
{
    g_print("Emit_My_Signal2() is called.\n");

    callNum++;
    GVariant *payload = g_variant_new("(is)", callNum, "Server Signal2");

    rtplay_gdbus_example_emit_my_signal2(pSkeleton, payload);

    return TRUE;
}

static gboolean My_Method1(RTplayGdbusExample *object, GDBusMethodInvocation *invocation, const gchar *in_arg)
{
    g_print("Server MyMethod1 call. Parameter: %s.\n", in_arg);

    in_arg = "Server My_Method1 to output.";

    rtplay_gdbus_example_complete_my_method1(object, invocation, in_arg);

    return TRUE;
}

static gboolean My_Method2(RTplayGdbusExample *object, GDBusMethodInvocation *invocation, GVariant *in_arg)
{
    gint in_arg1 = 0;
    gint in_arg2 = 0;
    gint out_arg2 = 0;
    gchar *out_arg1 = "Server MyMethod2 to output.";
    GVariant *out_arg = NULL;

    /** Get the input parameters */
    g_variant_get(in_arg, "(ii)", &in_arg1, &in_arg2);

    g_print("Server MyMethod2 call. Parameter: in_arg1 = %d , in_arg2 = %d.\n", in_arg1, in_arg2);

    /** Generate the output parameters */
    out_arg2 = in_arg1 + in_arg2;
    out_arg = g_variant_new("(si)", out_arg1, out_arg2);

    rtplay_gdbus_example_complete_my_method2(object, invocation, out_arg);

    return TRUE;
}

static void on_close_connection(GDBusConnection *connection, gboolean remote_peer_vanished, GError *error,
                                gpointer user_data)
{
    g_print("The %s connection [ %p ] was closed!\n", (char *)user_data, connection);
}

static gboolean on_new_connection(GDBusServer *server, GDBusConnection *connection, gpointer user_data)
{
    GError *_error = NULL;
    RTplayGdbusExampleIface *_iface;

    _iface = RTPLAY_GDBUS_EXAMPLE_GET_IFACE(pSkeleton);

    _iface->handle_my_method1 = My_Method1;
    _iface->handle_my_method2 = My_Method2;

    //导出interface_。
    g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(pSkeleton), connection, RTPLAY_GDBUS_EXAMPLE_OBJECT_PATH,
                                     &_error);

    if (_error != NULL) {
        g_print("Create new connection failed: [ %s ]\n", _error->message);
        g_error_free(_error);
    } else {
        g_print("A new connection [ %p ] was created\n", connection);
        g_signal_connect(connection, "closed", G_CALLBACK(on_close_connection), user_data);
    }

    return TRUE;
}

void *run(void *para)
{
    g_print("run call in the server.\n");
    /** Start the Main Event Loop which manages all available sources of events */
    g_main_loop_run(pLoop);

    return ((void *)0);
}

int thread_create(void)
{
    int err;
    pthread_t thr;

    err = pthread_create(&thr, NULL, run, NULL);

    if (err != 0) {
        g_print("Can't create thread: %s\n", strerror(err));
    } else {
        g_print("New thread created: %s\n", strerror(err));
    }

    return err;
}

bool InitDBusCommunicationServer(void)
{
    GError *_error = NULL;
    GDBusServer *_server;
    gchar *_guid;
    bool bRet = TRUE;

    g_print("InitDBusCommunicationServer: Server started.\n");

    /** create main loop, but do not start it. */
    pLoop = g_main_loop_new(NULL, FALSE);

    pSkeleton = rtplay_gdbus_example_skeleton_new();

    _guid = g_dbus_generate_guid();
    //创建一个新的D-Bus服务器，该服务器侦听有效address中的第一个地址。
    _server = g_dbus_server_new_sync("unix:abstract=gdbus_server", G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS,
                                     _guid, NULL, NULL, &_error);
    if (_error != NULL) {
        g_print("Create new server failed: [ %s ]", _error->message);
        g_error_free(_error);
        return bRet;
    }

    g_signal_connect(_server, "new-connection", G_CALLBACK(on_new_connection), NULL);
    //启动server。
    g_dbus_server_start(_server);

    /** emit my signal1 every 1 second to trigger example communication */
    g_timeout_add(1000, (GSourceFunc)Emit_My_signal1, NULL);

    /** emit my signal2 every 2 second to trigger example communication */
    g_timeout_add(2000, (GSourceFunc)Emit_My_Signal2, NULL);

    thread_create();

    return bRet;
}

bool DeinitDBusCommunicationServer(void)
{
    bool bRet = FALSE;
    if (0 != pLoop) {
        g_main_loop_quit(pLoop);
        g_main_loop_unref(pLoop);
        bRet = TRUE;
    }

    return bRet;
}